using System;
using System.Diagnostics;
using System.Text;

using Pegasus.Diagnostics;

namespace Pegasus
{
	/// <summary>
	/// 
	/// </summary>
	[ Serializable ]
	public class DateTimeReoccurringYearly : DateTimeReoccurring
	{
		// Local Instance Values
		private YearlyMode m_mode = YearlyMode.Mode1;
		private MonthOfYear m_month = MonthOfYear.January;
		private int m_dayOfMonth = 1;

		private WhichDay m_whichDay = WhichDay.First;
		private int m_dayOfWeek = (int) System.DayOfWeek.Sunday;


		/// <summary>
		/// Initializes a new instance of the <see cref="T:DateTimeReoccurringYearly"/> class.
		/// </summary>
		public DateTimeReoccurringYearly()
		{
		}

		/// <summary>
		/// Gets or sets the mode.
		/// </summary>
		/// <value>The mode.</value>
		public YearlyMode Mode
		{
			get
			{
				return m_mode;
			}
			set
			{
				m_mode = value;
			}
		}

		/// <summary>
		/// Gets or sets the month.
		/// </summary>
		/// <value>The month.</value>
		public MonthOfYear Month
		{
			get
			{
				return m_month;
			}
			set
			{
				m_month = value;
			}
		}

		/// <summary>
		/// Gets or sets the day of month.
		/// </summary>
		/// <value>The day of month.</value>
		public int DayOfMonth
		{
			get
			{
				return m_dayOfMonth;
			}
			set
			{
				ParamCode.Assert( value > 0 && value < 32, "DayOfMonth" );
				m_dayOfMonth = value;
			}
		}

		/// <summary>
		/// Gets or sets the which day.
		/// </summary>
		/// <value>The which day.</value>
		public WhichDay WhichDayOfMonth
		{
			get
			{
				return m_whichDay;
			}
			set
			{
				m_whichDay = value;
			}
		}

		/// <summary>
		/// Gets or sets the day of week.  Matches the DayOfWeek enumeration with the addtion
		/// of a value of 7 as the day (any day)
		/// </summary>
		/// <value>The day of week.</value>
		public int DayOfWeek
		{
			get
			{
				return m_dayOfWeek;
			}

			set
			{
				m_dayOfWeek = value;
			}
		}

		/// <summary>
		/// Get the date and time of the occurrance of the pattern from the
		/// given date time.
		/// </summary>
		/// <param name="fromDate">The date to calculate the pattern from.</param>
		/// <returns>
		/// A <see cref="DateTime"/> of the next occurance.
		/// </returns>
		public override DateTime GetNextOccurrence( DateTime fromDate )
		{
			DateTime baseDate = StartDate;
			DateTime nextDate = fromDate.Date + RunTime.TimeOfDay;

			if( m_mode == YearlyMode.Mode1 )
			{
				// Create a DateTime object for the day and month for this year
				nextDate = new DateTime( fromDate.Year, (int) m_month + 1, m_dayOfMonth ) + RunTime.TimeOfDay;

				// If date is passed then move to the next year.
				if( nextDate < fromDate )
				{
					nextDate = nextDate.AddYears( 1 );
				}
			}
			else
			{
				// Get the first of the month for the given month in this year
				DateTime firstOfTheMonth = new DateTime( fromDate.Year, (int) m_month + 1, 1 );
				nextDate = GetDayOfWeek( m_whichDay, m_dayOfWeek, firstOfTheMonth ) + RunTime.TimeOfDay;

				// If date is passed then move to the next year.
				if( nextDate < fromDate )
				{
					firstOfTheMonth = firstOfTheMonth.AddYears( 1 );
					nextDate = GetDayOfWeek( m_whichDay, m_dayOfWeek, firstOfTheMonth ) + RunTime.TimeOfDay;
				}
			}

			return nextDate;
		}

		/// <summary>
		/// Get the text description for the occurrence.
		/// </summary>
		/// <returns></returns>
		public override string GetDisplayText()
		{
			StringBuilder msg = new StringBuilder();

			if( m_mode == YearlyMode.Mode1 )
			{
				msg.Append( "Every " ).Append( m_month ).Append( " " ).Append( m_dayOfMonth );
			}
			else
			{
				msg.Append( "The " ).Append( m_whichDay.ToString().ToLower() );

				if( m_dayOfWeek == 7 )
				{
					msg.Append( " day" );
				}
				else
				{
					msg.Append( (DayOfWeek) m_dayOfWeek );
				}

				msg.Append( " of every " ).Append( m_month );
			}

			return msg.ToString();
		}

		/// <summary>
		/// Determine the mode to run in and which properties are used.
		/// </summary>
		public enum YearlyMode
		{
			/// <summary>
			/// Uses the Month and the DayOfMonth to set the pattern to run on 
			/// the specific day of the year.
			/// </summary>
			Mode1,

			/// <summary>
			/// Uses the WhichDayOfMonth, DayOfWeek, and Month to set the pattern to run on.
			/// </summary>
			Mode2,
		}

	}
}
